﻿#include "pch.h"
#include "sbhs.h"
#include "sbmath.h"

// 수학 - abs
static kint _math_abs(kScv* s)
{
	float a1;

	if (!k_scv_arg_type_float(s, 0, &a1))
		return KRR_ERROR;
	else
	{
		k_scv_push_float(s, k_abs(a1));
		return KRR_OK;
	}
}

// 수학 - sqrt
static kint _math_sqrt(kScv* s)
{
	float a1;

	if (!k_scv_arg_type_float(s, 0, &a1))
		return KRR_ERROR;
	else
	{
		k_scv_push_float(s, k_sqrt(a1));
		return KRR_OK;
	}
}

// 수학 - pow
static kint _math_pow(kScv* s)
{
	float a1, a2;

	if (!k_scv_arg_type_float(s, 0, &a1) ||
		!k_scv_arg_type_float(s, 1, &a2))
		return KRR_ERROR;
	else
	{
		k_scv_push_float(s, k_pow(a1, a2));
		return KRR_OK;
	}
}

// 수학 - floor
static kint _math_floor(kScv* s)
{
	float a1;

	if (!k_scv_arg_type_float(s, 0, &a1))
		return KRR_ERROR;
	else
	{
		k_scv_push_float(s, k_floor(a1));
		return KRR_OK;
	}
}

// 수학 - ceil
static kint _math_ceil(kScv* s)
{
	float a1;

	if (!k_scv_arg_type_float(s, 0, &a1))
		return KRR_ERROR;
	else
	{
		k_scv_push_float(s, k_ceil(a1));
		return KRR_OK;
	}
}

// 수학 - round
static kint _math_round(kScv* s)
{
	float a1;

	if (!k_scv_arg_type_float(s, 0, &a1))
		return KRR_ERROR;
	else
	{
		k_scv_push_float(s, k_floor(a1 + 0.5f));
		return KRR_OK;
	}
}

// 수학 - degtorad
static kint _math_torad(kScv* s)
{
	float a1;

	if (!k_scv_arg_type_float(s, 0, &a1))
		return KRR_ERROR;
	else
	{
		k_scv_push_float(s, k_torad(a1));
		return KRR_OK;
	}
}

// 수학 - radtodeg
static kint _math_todeg(kScv* s)
{
	float a1;

	if (!k_scv_arg_type_float(s, 0, &a1))
		return KRR_ERROR;
	else
	{
		k_scv_push_float(s, k_todeg(a1));
		return KRR_OK;
	}
}

// 수학 - sin
static kint _math_sin(kScv* s)
{
	float a1;

	if (!k_scv_arg_type_float(s, 0, &a1))
		return KRR_ERROR;
	else
	{
		k_scv_push_float(s, k_sin(a1));
		return KRR_OK;
	}
}

// 수학 - cos
static kint _math_cos(kScv* s)
{
	float a1;

	if (!k_scv_arg_type_float(s, 0, &a1))
		return KRR_ERROR;
	else
	{
		k_scv_push_float(s, k_cos(a1));
		return KRR_OK;
	}
}

// 수학 - cosh
static kint _math_cosh(kScv* s)
{
	float a1;

	if (!k_scv_arg_type_float(s, 0, &a1))
		return KRR_ERROR;
	else
	{
		k_scv_push_float(s, k_cosh(a1));
		return KRR_OK;
	}
}

// 수학 - tan
static kint _math_tan(kScv* s)
{
	float a1;

	if (!k_scv_arg_type_float(s, 0, &a1))
		return KRR_ERROR;
	else
	{
		k_scv_push_float(s, k_tan(a1));
		return KRR_OK;
	}
}

// 수학 - tanh
static kint _math_tanh(kScv* s)
{
	float a1;

	if (!k_scv_arg_type_float(s, 0, &a1))
		return KRR_ERROR;
	else
	{
		k_scv_push_float(s, k_tanh(a1));
		return KRR_OK;
	}
}

// 수학 - asin
static kint _math_asin(kScv* s)
{
	float a1;

	if (!k_scv_arg_type_float(s, 0, &a1))
		return KRR_ERROR;
	else
	{
		k_scv_push_float(s, k_asin(a1));
		return KRR_OK;
	}
}

// 수학 - acos
static kint _math_acos(kScv* s)
{
	float a1;

	if (!k_scv_arg_type_float(s, 0, &a1))
		return KRR_ERROR;
	else
	{
		k_scv_push_float(s, k_acos(a1));
		return KRR_OK;
	}
}

// 수학 - atan
static kint _math_atan(kScv* s)
{
	float a1;

	if (!k_scv_arg_type_float(s, 0, &a1))
		return KRR_ERROR;
	else
	{
		k_scv_push_float(s, k_atan(a1));
		return KRR_OK;
	}
}

// 수학 - atan2
static kint _math_atan2(kScv* s)
{
	float a1, a2;

	if (!k_scv_arg_type_float(s, 0, &a1) ||
		!k_scv_arg_type_float(s, 1, &a2))
		return KRR_ERROR;
	else
	{
		k_scv_push_float(s, k_atan2(a1, a2));
		return KRR_OK;
	}
}

// 수학 - log
static kint _math_log(kScv* s)
{
	float a1;

	if (!k_scv_arg_type_float(s, 0, &a1))
		return KRR_ERROR;
	else
	{
		k_scv_push_float(s, k_log(a1));
		return KRR_OK;
	}
}

// 수학 - log10
static kint _math_log10(kScv* s)
{
	float a1;

	if (!k_scv_arg_type_float(s, 0, &a1))
		return KRR_ERROR;
	else
	{
		k_scv_push_float(s, k_log10(a1));
		return KRR_OK;
	}
}

// 수학 - exp
static kint _math_exp(kScv* s)
{
	float a1;

	if (!k_scv_arg_type_float(s, 0, &a1))
		return KRR_ERROR;
	else
	{
		k_scv_push_float(s, k_exp(a1));
		return KRR_OK;
	}
}

// 수학 - min
static kint _math_min(kScv* s)
{
	float a1, a2;

	if (!k_scv_arg_type_float(s, 0, &a1) ||
		!k_scv_arg_type_float(s, 1, &a2))
		return KRR_ERROR;
	else
	{
		k_scv_push_float(s, k_min(a1, a2));
		return KRR_OK;
	}
}

// 수학 - max
static kint _math_max(kScv* s)
{
	float a1, a2;

	if (!k_scv_arg_type_float(s, 0, &a1) ||
		!k_scv_arg_type_float(s, 1, &a2))
		return KRR_ERROR;
	else
	{
		k_scv_push_float(s, k_max(a1, a2));
		return KRR_OK;
	}
}

// 수학 - clamp
static kint _math_clamp(kScv* s)
{
	float a1, a2, a3;

	if (!k_scv_arg_type_float(s, 0, &a1) ||
		!k_scv_arg_type_float(s, 1, &a2) ||
		!k_scv_arg_type_float(s, 2, &a3))
		return KRR_ERROR;
	else
	{
		k_scv_push_float(s, k_clamp(a1, a2, a3));
		return KRR_OK;
	}
}

// 수학 - clampradius
static kint _math_clrad(kScv* s)
{
	float a1;

	if (!k_scv_arg_type_float(s, 0, &a1))
		return KRR_ERROR;
	else
	{
		k_scv_push_float(s, k_cprad(a1));
		return KRR_OK;
	}
}

// 수학 - fract
static kint _math_fract(kScv* s)
{
	float a1;

	if (!k_scv_arg_type_float(s, 0, &a1))
		return KRR_ERROR;
	else
	{
		k_scv_push_float(s, k_fract(a1));
		return KRR_OK;
	}
}

// 수학 - prime
static kint _math_prime(kScv* s)
{
	kint a1;

	if (!k_scv_arg_type_int(s, 0, &a1))
		return KRR_ERROR;
	else
	{
		k_scv_push_int(s, (kint)k_primeclose(a1));
		return KRR_OK;
	}
}

// 수학 - rint
static kint _math_rint(kScv* s)
{
	float a1;

	if (!k_scv_arg_type_float(s, 0, &a1))
		return KRR_ERROR;
	else
	{
		k_scv_push_int(s, (kint)a1);
		return KRR_OK;
	}
}

// 수학 - rlong
static kint _math_rlong(kScv* s)
{
	double a1;

	if (!k_scv_arg_type_double(s, 0, &a1))
		return KRR_ERROR;
	else
	{
		k_scv_push_long(s, (klong)a1);
		return KRR_OK;
	}
}

// 랜덤 시드
static kint _rand_seed(kScv* s)
{
	kint arity = k_scv_arity(s);

	if (arity == 0)
		k_srand(0);
	else if (arity == 1)
	{
		kint seed;
		k_scv_arg_type_int(s, 0, &seed);
		k_srand((kuint)seed);
	}
	else
		return KRR_ERROR;

	return KRR_OK;
}

// 정수
static kint _rand_to_int(kScv* s)
{
	kint arity = k_scv_arity(s);
	kint rand;
	kint a1, a2;

	if (arity == 0)
		rand = k_rand_int((K_MIN_INT + 1) / 2, (K_MAX_INT - 1) / 2);
	else if (arity == 1)
	{
		k_scv_arg_type_int(s, 0, &a1);
		rand = k_rand_int(0, a1);
	}
	else if (arity == 2)
	{
		k_scv_arg_type_int(s, 0, &a1);
		k_scv_arg_type_int(s, 1, &a2);
		rand = k_rand_int(a1, a2);
	}
	else
		return KRR_ERROR;

	k_scv_push_int(s, rand);
	return KRR_OK;
}

// 롱
static kint _rand_to_long(kScv* s)
{
	kint arity = k_scv_arity(s);
	klong rand;
	klong a1, a2;

	if (arity == 0)
		rand = k_rand_long((K_MIN_LONG + 1) / 2, (K_MAX_LONG - 1) / 2);
	else if (arity == 1)
	{
		k_scv_arg_type_long(s, 0, &a1);
		rand = k_rand_long(0, a1);
	}
	else if (arity == 2)
	{
		k_scv_arg_type_long(s, 0, &a1);
		k_scv_arg_type_long(s, 1, &a2);
		rand = k_rand_long(a1, a2);
	}
	else
		return KRR_ERROR;

	k_scv_push_long(s, rand);
	return KRR_OK;
}

// 실수
static kint _rand_to_float(kScv* s)
{
	kint arity = k_scv_arity(s);
	float rand;
	float a1, a2;

	if (arity == 0)
		rand = k_rand_single(0.0f, 1.0f);
	else if (arity == 1)
	{
		k_scv_arg_type_float(s, 0, &a1);
		rand = k_rand_single(0.0f, a1);
	}
	else if (arity == 2)
	{
		k_scv_arg_type_float(s, 0, &a1);
		k_scv_arg_type_float(s, 1, &a2);
		rand = k_rand_single(a1, a2);
	}
	else
		return KRR_ERROR;

	k_scv_push_float(s, rand);
	return KRR_OK;
}

// 더블
static kint _rand_to_double(kScv* s)
{
	kint arity = k_scv_arity(s);
	double rand;
	double a1, a2;

	if (arity == 0)
		rand = k_rand_double(0.0f, 1.0f);
	else if (arity == 1)
	{
		k_scv_arg_type_double(s, 0, &a1);
		rand = k_rand_double(0.0, a1);
	}
	else if (arity == 2)
	{
		k_scv_arg_type_double(s, 0, &a1);
		k_scv_arg_type_double(s, 1, &a2);
		rand = k_rand_double(a1, a2);
	}
	else
		return KRR_ERROR;

	k_scv_push_double(s, rand);
	return KRR_OK;
}

//
static void _math_reg_const(kRedTbl* tbl, const char* name, float value)
{
	kVar kk, vv;
	k_var_set_sym_static(&kk, name);
	k_var_set_float(&vv, value);
	k_redtbl_unsafe_append(tbl, &kk, &vv, k_redtbl_key_hash(&kk));
}

//
kuint k_hlib_math(kHsm* hsm)
{
	static const struct khParamFuncReg mathmtds[] =
	{
#define MAPMTD(name)		KHPARAM_FUNC_REG_SIMPLE(K_STRING(name), K_CONCAT(_math_,name))
		MAPMTD(abs),
		MAPMTD(sqrt),
		MAPMTD(pow),
		MAPMTD(floor),
		MAPMTD(ceil),
		MAPMTD(round),
		MAPMTD(torad),
		MAPMTD(todeg),
		MAPMTD(sin),
		MAPMTD(cos),
		MAPMTD(cosh),
		MAPMTD(tan),
		MAPMTD(tanh),
		MAPMTD(asin),
		MAPMTD(acos),
		MAPMTD(atan),
		MAPMTD(atan2),
		MAPMTD(log),
		MAPMTD(log10),
		MAPMTD(exp),
		MAPMTD(min),
		MAPMTD(max),
		MAPMTD(clamp),
		MAPMTD(clrad),
		MAPMTD(fract),
		MAPMTD(prime),
		MAPMTD(rint),
		MAPMTD(rlong),
#undef MAPMTD
#define MAPMNG(name,func)	KHPARAM_FUNC_REG_SIMPLE(name, K_CONCAT(_rand_,func))
		MAPMNG("srand", seed),
		MAPMNG("rand", to_int),
#undef MAPMNG
	};
	static const struct khParamFuncReg randmtds[] =
	{
#define MAPMNG(name,func)	KHPARAM_FUNC_REG_SIMPLE(name, K_CONCAT(_rand_,func))
		MAPMNG("Seed", seed),
		MAPMNG("ToInt", to_int),
		MAPMNG("ToLong", to_long),
		MAPMNG("ToFloat", to_float),
		MAPMNG("ToDouble", to_double),
#undef MAPMNG
	};

	kRedTbl* tbl;

	if (k_hsm_reg_lib(hsm, KHLIB_MATH))
		return 0;

	//
	k_hsm_bind_libs(hsm, NULL, K_COUNTOF(mathmtds), mathmtds, &tbl);

	//
	k_hsm_bind_libs(hsm, "Math", 0, NULL, &tbl);
	_math_reg_const(tbl, "Pi", KM_PI);
	_math_reg_const(tbl, "Pi2", KM_PI_2);
	_math_reg_const(tbl, "PiHalf", KM_PI_HALF);
	_math_reg_const(tbl, "PiHoH", KM_PI_HOH);
	_math_reg_const(tbl, "E", KM_E);
	_math_reg_const(tbl, "Log2e", KM_LOG2E);
	_math_reg_const(tbl, "Log10e", KM_LOG10E);
	_math_reg_const(tbl, "Log2b10", KM_LOG2B10);
	_math_reg_const(tbl, "Ln2", KM_LN2);
	_math_reg_const(tbl, "Ln10", KM_LN10);
	_math_reg_const(tbl, "Sqrt2", KM_SQRT2);
	_math_reg_const(tbl, "SqrtHalf", KM_SQRT_HALF);

	//
	k_hsm_bind_libs(hsm, "Rand", K_COUNTOF(randmtds), randmtds, NULL);

	return KHLIB_MATH;
}
